import java.util.Collections;
import java.util.Vector;
import java.util.concurrent.*;

/**
 * 闭锁测试
 */
public class Main {

    public static void main(String[] args) throws Exception{

        /*
同步容器  如Vector ，Hashtable，Collections.synchronizedList(),其实就是加一把锁(synchronized)，线程排队,你执行完成我才能进入,已经淘汰，基本不这样写了
在一个线程中迭代一个Vector的过程中，另一个线程把这个Vector修改了，
这时候会报一个并发修改异常。所以一般在迭代的时候要锁定线程，但是锁定了以后别的线程就访问不到这个Vector了。
这时候可以在需要修改的线程中独立拷贝一份集合。

并发容器
  ConcurrentHashMap采用了分段锁的技术 用的多。方法：putAbscent()如果这个键不存在，才插入。在CAS问题中非常重要
CopyOnWriteArrayList/Set  杜操作大部分，写操作少的时候用.
阻塞队列：BlockingQueue  如果队列为空就阻塞了。
闭锁 栅栏 信号量
闭锁是：一种同步方法，可以延迟线程的进度直到线程到达某个终点状态。通俗的讲就是，一个闭锁相当于一扇大门，在大门打开之前所有线程都被阻断，一旦大门打开所有线程都将通过，但是一旦大门打开，所有线程都通过了，那么这个闭锁的状态就失效了，门的状态也就不能变了，只能是打开状态。
CountDownLatch是JDK 5+里面闭锁的一个实现，允许一个或者多个线程等待某个事件的发生。CountDownLatch有一个正数计数器，countDown方法对计数器做减操作，await方法等待计数器达到0。所有await的线程都会阻塞直到计数器为0或者等待线程中断或者超时。
栅栏与闭锁的关键区别在于，所有的线程必须同时到达栅栏位置，才能继续执行。闭锁用于等待事件，而栅栏用于等待其他线程。
栅栏：
Semaphore是用来保护一个或者多个共享资源的访问，Semaphore内部维护了一个计数器，其值为可以访问的共享资源的个数。一个线程要访问共享资源，先获得信号量，如果信号量的计数器值大于1，意味着有共享资源可以访问，则使其计数器值减去1，再访问共享资源。

如果计数器值为0,线程进入休眠。当某个线程使用完共享资源后，释放信号量，并将信号量内部的计数器加1，之前进入休眠的线程将被唤醒并再次试图获得信号量。

就好比一个厕所管理员，站在门口，只有厕所有空位，就开门允许与空侧数量等量的人进入厕所。多个人进入厕所后，相当于N个人来分配使用N个空位。为避免多个人来同时竞争同一个侧卫，在内部仍然使用锁来控制资源的同步访问。
         */

        final CountDownLatch latch = new CountDownLatch(2);//等待2个线程完成后，执行latch.wait那个线程才会继续执行
        new Thread(){
            @Override
            public void run() {

                try {
                    Thread.sleep(3000);
                    System.out.println("子线程1执行");
                    latch.countDown();//执行这条语句后，latch就知道有一个线程结束了
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        new Thread(){
            @Override
            public void run() {

                try {
                    Thread.sleep(3000);
                    System.out.println("子线程2执行");
                    latch.countDown();//执行这条语句后，latch就知道有一个线程结束了
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

        System.out.println("主线程正在等待");
        latch.await();
        System.out.println("主线程完成");


    }
}
